﻿using System;
using System.Collections.Generic;
using System.Reflection;
using CoreEx.Wcf.Common.Implementation;
using LinFu.IoC.Interfaces;
using LinFu.Reflection;
using CoreEx.Common.Extensions;
using System.Linq;
namespace CoreEx.Wcf.Common.Implementation
{
    /// <summary>
    /// Provides a default implementation of the <see cref="ITypeResolver"/> interface.     
    /// </summary>
    /// <remarks>
    /// This implementation will load all the types from the directory where the executing <see cref="Assembly"/> is located.
    /// In order to provide more control over the list of known types, implement the <see cref="IFactory{T}"/> interface to create 
    /// a custom implementation of the <see cref="ITypeResolver"/> interface.
    /// You can also inherit from the <see cref="KnownTypesResolver"/> and override the <see cref="SearchPattern"/> property in order 
    /// to filter the assemblies that contains types that is to considered as known types.
    /// </remarks>
    public abstract class TypeResolver : ITypeResolver
    {
        private static IList<Type> _knownTypes;

        /// <summary>
        /// Returns a list of known types
        /// </summary>
        /// <returns><see cref="IList{Type}"/></returns>
        public IEnumerable<Type> GetTypes()
        {
            
            var loader = new Loader<IList<Type>>();
            var targetLoader = new AssemblyTargetLoader<IList<Type>>();
            ((AssemblyActionLoader<IList<Type>>)targetLoader.AssemblyActionLoader).TypeExtractor = new TypeExtractor();
            targetLoader.TypeLoaders.Add(new TypeActionLoader());
            loader.FileLoaders.Add(targetLoader);
            _knownTypes = new List<Type>();
            loader.LoadDirectory(Assembly.GetExecutingAssembly().GetDirectory(), SearchPattern);
            loader.LoadInto(_knownTypes);            
            ApplyCustomTypes(_knownTypes);
            return _knownTypes.Where(IsValidType);
        }


        /// <summary>
        /// Gets or sets the search pattern to be used when searching for assemblies.
        /// </summary>
        public string SearchPattern { get; set; }


        public virtual bool IsValidType(Type type)
        {
            return true;
        }

        public virtual void ApplyCustomTypes(IList<Type> validTypes) {}
        
    }
}